﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Contracts;
using System.Linq;

namespace Postnuclear
  {
  /// <summary>
  /// The extension methods for the <see cref="IEnumerable{T}"/>.
  /// </summary>  
  public static partial class ExtensionMethods
    {
    #region Public

    // Methods

    /// <summary>
    /// Execute some code for each element of collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements of source.</typeparam>
    /// <param name="source">An <see cref="IEnumerable{T}"/>.</param>
    /// <param name="handler">The handler.</param>
    [DebuggerHidden]
    public static void ForEach<T>(this IEnumerable<T> source, Action<T> handler)
      {
      Contract.Requires<ArgumentNullException>(source != null);
      Contract.Requires<ArgumentNullException>(handler != null);

      source.ForEach((item, _) => handler(item));
      }

    /// <summary>
    /// Execute some code for each element of collection.
    /// </summary>
    /// <typeparam name="T">The type of the elements of source.</typeparam>
    /// <param name="source">An <see cref="IEnumerable{T}"/>.</param>
    /// <param name="handler">The handler.</param>
    [DebuggerHidden]
    public static void ForEach<T>(this IEnumerable<T> source, Action<T, int> handler)
      {
      Contract.Requires<ArgumentNullException>(source != null);
      Contract.Requires<ArgumentNullException>(handler != null);

      int index = 0;
      foreach (T element in source)
        {
        handler(element, index++);
        }
      }

    /// <summary>
    /// Gets the index of item in source collection.
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of the input sequence.</typeparam>
    /// <param name="source">The source sequence.</param>
    /// <param name="item">The specified item.</param>
    /// <returns>The index of specified item in source sequence.</returns>
    [DebuggerHidden]
    public static int IndexOf<TSource>(this IEnumerable<TSource> source, TSource item)
      {
      int index = 0;

      foreach (TSource element in source)
        {
        if (object.Equals(item, element))
          {
          return index;
          }

        ++index;
        }

      return -1;
      }

    /// <summary>
    /// Determines whether two sequences are equal by comparing the elements by using
    /// the comparer delegate .
    /// </summary>
    /// <typeparam name="TSource">The type of the elements of the first sequence.</typeparam>
    /// <typeparam name="TTarget">The type of the elements of the second sequence.</typeparam>
    /// <param name="first">An <see cref="IEnumerable{T}"/> to compare to second.</param>
    /// <param name="second">An <see cref="IEnumerable{T}"/> to compare to first.</param>
    /// <param name="comparer">An delegate to use to compare elements.</param>
    /// <returns>
    /// <c>true</c> if the two source sequences are of equal length and their corresponding elements are equal 
    /// according to the specified equality comparer for their types;
    /// otherwise, <c>false</c>.
    /// </returns>
    [DebuggerHidden]
    public static bool SequenceEqual<TSource, TTarget>(this IEnumerable<TSource> first, IEnumerable<TTarget> second, Func<TSource, TTarget, bool> comparer)
      {
      TSource[] source = first.ToArray();
      TTarget[] target = second.ToArray();

      if (source.Length != target.Length)
        {
        return false;
        }

      return !source.Where((t, i) => !comparer(t, target[i])).Any();
      }

    #endregion
    }
  }